package com.smilive.start.netty.chat.client;

import com.smilive.start.netty.chat.message.ChatRequestMessage;
import com.smilive.start.netty.chat.message.LoginRequestMessage;
import com.smilive.start.netty.chat.message.LoginResponseMessage;
import com.smilive.start.netty.chat.peotocol.MessageCodecSharable;
import com.smilive.start.netty.chat.peotocol.ProtocolFrameDecoder;
import com.smilive.start.netty.chat.peotocol.ClientChannelDuplexHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @program: netty
 * @Date: 2022-01-06 11:41
 * @Author: smilive
 * @Description:
 */
@Slf4j
public class ChatClient {
    public static void main(String[] args) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        //用来阻塞线程,等待登入结果
        CountDownLatch WAIT_LOGIN = new CountDownLatch(1);
        //登入结果,使用AtomicBoolean 使其保持线程可见性
        AtomicBoolean LOGIN_RESULT = new AtomicBoolean(false);
        //抽取线程安全的Handler,减少类的创建
        LoggingHandler LOG_HANDLER = new LoggingHandler(LogLevel.DEBUG);
        MessageCodecSharable MAG_HANDLER = new MessageCodecSharable();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.channel(NioSocketChannel.class)
                    .group(group)
                    .handler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel ch) throws Exception {
                            // 发送心跳包，让服务器知道客户端在线
                            // 3s未发生WRITER_IDLE，就像服务器发送心跳包
                            // 该值为服务器端设置的READER_IDLE触发时间的一半左右
                            ch.pipeline().addLast(new IdleStateHandler(0, 5, 0));
                            // 开辟额外线程，用于用户登陆及后续操作
                            //粘包,半包处理器
                            ch.pipeline().addLast(new ProtocolFrameDecoder());
                            ch.pipeline().addLast(LOG_HANDLER);
                            ch.pipeline().addLast(MAG_HANDLER);
                            ch.pipeline().addLast(new ClientChannelDuplexHandler());
                            ch.pipeline().addLast("chatClient",new ChannelInboundHandlerAdapter(){
                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    if (msg instanceof LoginResponseMessage){
                                        LoginResponseMessage loginResponseMessage = (LoginResponseMessage) msg;
                                        if (loginResponseMessage.isSuccess()){
                                            LOGIN_RESULT.set(true);
                                        }
                                        WAIT_LOGIN.countDown();
                                    }
                                }

                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                    new Thread(()->{
                                        Scanner scanner = new Scanner(System.in);
                                        System.out.println("请输入用户名:");
                                        String name = scanner.next();
                                        System.out.println("请输入密码:");
                                        String pwad = scanner.next();
                                        //创建登入信息请求体
                                        LoginRequestMessage loginRequestMessage = new LoginRequestMessage(name, pwad);
                                        ctx.writeAndFlush(loginRequestMessage);
                                        System.out.println("登入中...");
                                        try {
                                            WAIT_LOGIN.await();
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }
                                        if (!LOGIN_RESULT.get()){
                                            System.out.println("登入失败");
                                            ctx.channel().close();
                                            return;
                                        }
                                        // 登录成功后，执行其他操作
                                        while (true) {
                                            System.out.println("==================================");
                                            System.out.println("send [username] [content]");
                                            System.out.println("gsend [group name] [content]");
                                            System.out.println("gcreate [group name] [m1,m2,m3...]");
                                            System.out.println("gmembers [group name]");
                                            System.out.println("gjoin [group name]");
                                            System.out.println("gquit [group name]");
                                            System.out.println("quit");
                                            System.out.println("==================================");
                                            String command = scanner.nextLine();
                                            // 获得指令及其参数，并发送对应类型消息
                                            String[] commands = command.split(" ");
                                            switch (commands[0]){
                                                case "send":
                                                    ctx.writeAndFlush(new ChatRequestMessage(name, commands[1], commands[2]));
                                                    break;
                                                case "quit":
                                                    ctx.channel().close();
                                                    return;
                                                default:
                                                    System.out.println("指令有误，请重新输入");
                                                    continue;
                                            }
                                        }

                                    },"system in").start();


                                }
                            });

                        }
                    });
            Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel();
            channel.closeFuture().sync();
        }catch (Exception e){
            log.error("client error:",e);
        }finally {
            group.shutdownGracefully();
        }


    }

}
